package Log

import (
	"fmt"
	"log"
	"os"
	"sync"
	"time"
)

type Writer struct {
	BaseWriter
	File      *os.File
	msgChan   chan string
	waitGroup *sync.WaitGroup //针对 msgChan 创建等待组，避免消息没写完 Writer 就提前关闭
}

func (w *Writer) Write(msg string) {
	w.waitGroup.Add(1)
	//fmt.Println(msg)
	w.msgChan <- msg
}

func (w *Writer) waiteMsg() {
	for msg := range w.msgChan {
		//runtime.Gosched()
		w.File.WriteString(msg)
		w.waitGroup.Done()
	}
	// 并发10个连接， 管道存取耗CPU约 16%（68-52）  文件写入耗CPU约 5%（73-68）
}

func (w *Writer) Close() {
	w.waitGroup.Wait()
	close(w.msgChan)
	w.File.Close()
}
func (w *Writer) Wait() {
	w.waitGroup.Wait()
}

//创建或更换日志文件
func (w *Writer) NewFile(FilePath, FileName string) {
	if err := os.MkdirAll(FilePath, os.FileMode(0755)); err != nil {
		log.Fatal("创建文件夹", FilePath, "失败")
	}
	file, err := os.OpenFile(FilePath+FileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) //追加
	if err != nil {
		file.Close()
		log.Fatal(fmt.Sprintf("打开日志文件[%s]失败", FilePath+FileName))
	}
	if w.File != nil { //替换原有日志文件前先关闭原有文件，释放资源
		oldFile := w.File
		go func() { //延时关闭原文件，避免关闭原有文件时正在执行写入操作而报错
			<-time.After(5 * time.Minute)
			oldFile.Close()
		}()
	}
	w.File = file
}

func NewWriter(filePath, fileName string) *Writer {
	wr := &Writer{
		msgChan:   make(chan string, 99999),
		waitGroup: new(sync.WaitGroup),
	}
	wr.NewFile(filePath, fileName)
	go wr.waiteMsg()
	return wr
}
